home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / ddj0492.zip / STRUCPRG.ASC < prev    next >
Text File  |  1992-03-10  |  8KB  |  248 lines

  1. _STRUCTURED PROGRAMMING COLUMN_
  2. by Jeff Duntemann
  3.  
  4.  
  5. [LISTING ONE]
  6.  
  7. UNIT DirList;  { By Jeff Duntemann; for DDJ 4/92 }
  8.  
  9. INTERFACE
  10.  
  11. USES Crt,DOS,Objects,  { Standard Borland units }
  12.      When2;            { From DDJ 1/91          }
  13. TYPE
  14.   String40  = STRING[40];
  15.   PDirEntry = ^TDirEntry;
  16.   TDirEntry =
  17.     OBJECT(TObject)
  18.       Path  : PathStr;      { Predefined in Dos unit as STRING[79] }
  19.       Entry : SearchRec;      { Also predefined in the Dos unit    }
  20.       DirLine : String40;     { Preformatted directory info string }
  21.       CONSTRUCTOR Init(APath : PathStr; ASearchRec : SearchRec);
  22.       PROCEDURE   FormatDirLine;
  23.     END;
  24.   PDirEntryCollection = ^TDirEntryCollection;
  25.   TDirEntryCollection =
  26.    OBJECT(TSortedCollection)
  27.     CONSTRUCTOR InitDir(ALimit,ADelta : Integer;
  28.                         Path, Mask    : STRING;
  29.                         Attr          : Word);
  30.     CONSTRUCTOR InitCommandLine(ALimit,ADelta : Integer; StartParam : Integer);
  31.     CONSTRUCTOR InitTree(Alimit,ADelta : Integer;
  32.                          Path,Mask     : STRING;
  33.                          Attr          : Word);
  34.     FUNCTION    Compare(Key1,Key2 : Pointer) : Integer; VIRTUAL;
  35.     PROCEDURE   AddDir(Path,Mask : STRING;
  36.                        Attr      : Word);
  37.     PROCEDURE   TreeScan(Path,Mask : STRING; Attr : Word);
  38.    END;
  39.  
  40. IMPLEMENTATION
  41. VAR
  42.   Stamp : When;  { Global When stamp for time/date string processing }
  43. {----------------------------------------}
  44. { Methods: TDirEntry                     }
  45. {----------------------------------------}
  46. CONSTRUCTOR TDirEntry.Init(APath : PathStr; ASearchRec : SearchRec);
  47. BEGIN
  48.   TObject.Init;
  49.   Path  := APath;
  50.   Entry := ASearchRec;
  51.   FormatDirLine;
  52. END;
  53. PROCEDURE TDirEntry.FormatDirLine;
  54. VAR
  55.   DotPos : Integer;
  56.   WorkString,Blanker : String40;
  57. BEGIN
  58.   Stamp.PutWhenStamp(Entry.Time);
  59.   DirLine := '                                        ';
  60.   Blanker := DirLine;
  61.   {If the entry has the directory attribute, format differently: }
  62.   IF (Entry.Attr AND $10) <> 0 THEN { Bit 4 is the directory attribute }
  63.     BEGIN
  64.       Insert(Entry.Name,DirLine,1); { No extensions on subdirectory names }
  65.       Insert('<DIR>',DirLine,14)    { Tell the world it's a subdirectory  }
  66.     END
  67.   ELSE
  68.     {This compound statement separates the file from its extension  }
  69.     { and converts the file size to a string.  Note that we did not }
  70.     { insert a file size figure into DirLine for subdirectory entries. }
  71.     BEGIN
  72.       DotPos := Pos('.',Entry.Name);
  73.       IF DotPos > 0 THEN  { File name has an extension }
  74.         WorkString := Copy(Entry.Name,1,DotPos-1) +
  75.           Copy(Blanker,1,9-DotPos) + '.' +
  76.           Copy(Entry.Name,DotPos+1,Length(Entry.Name)-DotPos)
  77.       ELSE                       { File name has no extension }
  78.         WorkString := Entry.Name +
  79.                       Copy(Blanker,1,8-Length(Entry.Name)) + '.';
  80.       Insert(WorkString,DirLine,1);
  81.       Str(Entry.Size:7,WorkString);
  82.       Insert(WorkString,DirLine,15);
  83.     END;
  84.   Insert(Stamp.GetDateString,DirLine,24);
  85.   Insert(Stamp.GetTimeString,DirLine,34);  { Finally, insert the time }
  86.   Delete(DirLine,42,Length(DirLine)-42);
  87. END;
  88. {----------------------------------------}
  89. { Methods: TDirEntryCollection           }
  90. {----------------------------------------}
  91. CONSTRUCTOR TDirEntryCollection.InitDir(ALimit,ADelta : Integer;
  92.                                         Path,Mask : STRING;
  93.                                         Attr      : Word);
  94. BEGIN
  95.   TSortedCollection.Init(Alimit,ADelta);
  96.   AddDir(Path,Mask,Attr);
  97. END;
  98.  
  99. CONSTRUCTOR TDirEntryCollection.InitCommandLine(ALimit,ADelta : Integer;
  100.                                                 StartParam : Integer);
  101. VAR
  102.   I     : Integer;
  103.   SR    : SearchRec;     { Defined in the Dos unit }
  104.   DEP   : PDirEntry;
  105.   Path  : PathStr;       { Defined in the Dos unit as STRING[79]; }
  106.   Dir   : DirStr;        { Defined in the Dos unit as STRING[67]; }
  107.   Name  : NameStr;       { Defined in the Dos unit as STRING[8];  }
  108.   Ext   : ExtStr;        { Defined in the Dos unit as STRING[4];  }
  109. BEGIN
  110.   TSortedCollection.Init(ALimit,ADelta);
  111.   FOR I := StartParam TO ParamCount DO
  112.     BEGIN
  113.       FSplit(ParamStr(I),Dir,Name,Ext);
  114.       AddDir(Dir,Name+Ext,AnyFile);
  115.     END;
  116. END;
  117.  
  118. CONSTRUCTOR TDirEntryCollection.InitTree(Alimit,ADelta : Integer;
  119.                                          Path,Mask     : STRING;
  120.                                          Attr          : Word);
  121. BEGIN
  122.   TSortedCollection.Init(Alimit,ADelta);
  123.   TreeScan(Path,Mask,Attr);
  124. END;
  125.  
  126. FUNCTION TDirEntryCollection.Compare(Key1,Key2 : Pointer) : Integer;
  127. BEGIN
  128.   IF (PDirEntry(Key1)^.Path + PDirEntry(Key1)^.Entry.Name) =
  129.      (PDirEntry(Key2)^.Path + PDirEntry(Key2)^.Entry.Name) THEN
  130.     Compare := 0
  131.   ELSE
  132.   IF (PDirEntry(Key1)^.Path + PDirEntry(Key1)^.Entry.Name) <
  133.      (PDirEntry(Key2)^.Path + PDirEntry(Key2)^.Entry.Name) THEN
  134.     Compare := -1
  135.   ELSE Compare := 1;
  136. END;
  137.  
  138. PROCEDURE TDirEntryCollection.AddDir(Path,Mask : STRING;
  139.                                      Attr      : Word);
  140. VAR
  141.   I     : Integer;
  142.   SR    : SearchRec;
  143.   DEP   : PDirEntry;
  144. BEGIN
  145.   FindFirst(Path+Mask,Attr,SR);
  146.   IF DosError = 0 THEN
  147.     BEGIN
  148.       DEP := New(PDirEntry,Init(Path,SR));
  149.       Insert(DEP);
  150.       REPEAT
  151.         FindNext(SR);
  152.         IF DosError = 0 THEN
  153.           BEGIN
  154.             DEP := New(PDirEntry,Init(Path,SR));
  155.             Insert(DEP);
  156.           END;
  157.       UNTIL DosError <> 0;
  158.     END;
  159. END;
  160.  
  161. PROCEDURE TDirEntryCollection.TreeScan(Path,Mask : STRING;
  162.                                        Attr : Word);
  163. VAR
  164.   I     : Integer;
  165.   SR    : SearchRec;
  166.   DEP   : PDirEntry;
  167.   NextDirectory : STRING;
  168. BEGIN
  169.   fillchar(SR,sizeof(SR),0);
  170.   { We look for and search any subdirectories first: }
  171.   IF Path <> '\' THEN Path := Path + '\';
  172.   FindFirst(Path+'*.*',Directory,SR);
  173.   WHILE (DOSError <> 2) AND (DOSError <> 18) DO
  174.     BEGIN
  175.       IF ((SR.Attr AND Directory) = Directory )
  176.       AND (SR.Name[1] <> '.') THEN  { We have a subdirectory }
  177.         BEGIN
  178.           NextDirectory := Path + SR.Name;
  179.           TreeScan(NextDirectory,Mask,Attr);
  180.         END;
  181.       FindNext(SR);
  182.     END;
  183.   { At this point, we're in a directory that has no unsearched }
  184.   { subdirectories, so we can search for files matching Mask:  }
  185.   AddDir(Path,Mask,Attr);
  186. END;
  187.  
  188. { No initialization section }
  189. END.
  190.  
  191.  
  192.  
  193. [LISTING TWO]
  194.  
  195. PROGRAM JFind;  { By Jeff Duntemann; from DDJ 4/92 }
  196.  
  197. USES DOS,CRT,Printer,  { Standard Borland units }
  198.      DirList;          { From DDJ for 4/92      }
  199. VAR
  200.   Console    : TEXT;
  201.   FileSpecs  : STRING;
  202.   I          : Integer;
  203.   FilesFound : PDirEntryCollection;
  204.  
  205. PROCEDURE DisplayFoundFiles(FilesFound : PDirEntryCollection);
  206. { This is the FAR local routine passed to the iterator method. }
  207. { It's called once for each item in the collection: }
  208. PROCEDURE DisplayOneFile(Target : PDirEntry); FAR;
  209. BEGIN
  210.   Write(Console,Copy(Target^.DirLine,13,Length(Target^.DirLine)),' ');
  211.   Writeln(Console,Target^.Path,Target^.Entry.Name);
  212. END;
  213.  
  214. BEGIN
  215.   { This is how you iterate a procedure over a collection: }
  216.   FilesFound^.ForEach(@DisplayOneFile);
  217. END;
  218.  
  219. BEGIN                     { JFIND Main }
  220.   Assign(Console,'');     { This allows us to use Standard Output }
  221.   Rewrite(Console);       {  for Write/Writeln statements         }
  222.   IF ParamCount = 0 THEN
  223.     BEGIN
  224.       Writeln(Console,'>>>JFIND<<< by Jeff Duntemann');
  225.       Writeln(Console);
  226.       Writeln(Console,'Invocation syntax:');
  227.       Writeln(Console);
  228.       Writeln(Console,'  JFIND <filespec>,[<filespec>..] CR');
  229.       Writeln(Console);
  230.     END
  231.   ELSE
  232.     BEGIN
  233.       FilesFound := New(PDirEntryCollection,Init(256,16));
  234.       FOR I := 1 TO ParamCount DO
  235.         FilesFound^.TreeScan('\',ParamStr(I),AnyFile);
  236.       IF FilesFound^.Count > 0 THEN
  237.         BEGIN
  238.           DisplayFoundFiles(FilesFound);
  239.           Writeln(Console);
  240.         END
  241.       ELSE
  242.         Writeln(Console,'No files match that file spec.');
  243.     END;
  244. END.
  245.  
  246.  
  247.  
  248.